package com.qd.core.dblog;

import com.cdqidi.exception.QueueIsEmptyException;
import com.cdqidi.util.SpringContextHolder;
import com.qd.core.dblog.thread.*;
import com.qd.system.model.*;
import com.qd.system.service.log.*;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class LogProcess {
    private LogProcess() {

    }

    private static class SingletonHolder {
        private static final LogProcess INSTANCE = new LogProcess();
    }

    public static LogProcess getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /**
     * 审计日志
     */
    private final LinkedList<DataLog> dataLogs = new LinkedList<>();
    /**
     * 审计日志处理线程
     */
    private final List<ProcessDataLogThread> processDataLogThreadList = new ArrayList<>();

    private boolean operatorLogStatus;
    /**
     * 操作日志
     */
    private final LinkedList<OperatorLog> operatorLogs = new LinkedList<>();
    /**
     * 操作日志处理线程
     */
    private final List<ProcessOperatorLogThread> processOperatorLogThreadList = new ArrayList<>();

    private boolean  loginLogStatus;
    /**
     * 登录日志
     */
    private final LinkedList<LoginLog> loginLogs = new LinkedList<>();
    /**
     * 登录日志处理线程
     */
    private final List<ProcessLoginLogThread> processLoginLogThreadList = new ArrayList<>();

    private boolean  receiveLogStatus;
    /**
     * 接收日志
     */
    private final LinkedList<ReceiveLog> receiveLogs = new LinkedList<>();
    /**
     * 接收日志处理线程
     */
    private final List<ProcessReceiveLogThread> processReceiveLogThreadList = new ArrayList<>();

    private boolean  sendLogStatus;
    /**
     * 发送日志
     */
    private final LinkedList<SendLog> sendLogs = new LinkedList<>();
    /**
     * 发送日志处理线程
     */
    private final List<ProcessSendLogThread> processSendLogThreadList = new ArrayList<>();


    public void addDataLogs(List<DataLog> list) {
        synchronized (dataLogs) {
            dataLogs.addAll(list);
            dataLogs.notifyAll();
        }
    }

    public int getDataLogSize() {
        synchronized (dataLogs) {
            return dataLogs.size();
        }
    }

    public void getDataLogs(List<DataLog> dataList) throws QueueIsEmptyException, InterruptedException {
        synchronized (dataLogs) {
            if (dataLogs.isEmpty()) {
                try {
                    dataLogs.wait(5000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw e;
                }
                if (!dataLogs.isEmpty()) {
                    fillDataLogs(dataList);
                    return;
                }
                throw new QueueIsEmptyException();
            } else {
                fillDataLogs(dataList);
            }
        }
    }

    private void fillDataLogs(List<DataLog> dataList) {
        if (dataLogs.size() > 99) {
            int c = 0;
            while (!dataLogs.isEmpty()) {
                dataList.add(dataLogs.remove());
                c++;
                if (c > 99) {
                    break;
                }
            }
        } else {
            dataList.addAll(dataLogs);
            dataLogs.clear();
        }
    }
    public void addOperatorLog(OperatorLog operatorLog) {
        synchronized (operatorLogs) {
            operatorLogs.add(operatorLog);
            if (operatorLogStatus) {
                operatorLogStatus = false;
                operatorLogs.notifyAll();
            }
        }
    }

    public int getOperatorLogSize() {
        synchronized (operatorLogs) {
            return operatorLogs.size();
        }
    }

    public void getOperatorLogs(List<OperatorLog> dataList) throws QueueIsEmptyException, InterruptedException {
        synchronized (operatorLogs) {
            if (operatorLogs.isEmpty()) {
                operatorLogStatus = true;
                try {
                    operatorLogs.wait(5000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw e;
                }
                if (!operatorLogs.isEmpty()) {
                    operatorLogStatus = false;
                    fillOperatorLogs(dataList);
                    return;
                }
                throw new QueueIsEmptyException();
            } else {
                fillOperatorLogs(dataList);
            }
        }
    }

    private void fillOperatorLogs(List<OperatorLog> dataList) {
        if (operatorLogs.size() > 99) {
            int c = 0;
            while (!operatorLogs.isEmpty()) {
                dataList.add(operatorLogs.remove());
                c++;
                if (c > 99) {
                    break;
                }
            }
        } else {
            dataList.addAll(operatorLogs);
            operatorLogs.clear();
        }
    }

    public void addLoginLog(LoginLog loginLog) {
        synchronized (loginLogs) {
            loginLogs.add(loginLog);
            if (loginLogStatus) {
                loginLogStatus = false;
                loginLogs.notifyAll();
            }
        }
    }

    public int getLoginLogSize() {
        synchronized (loginLogs) {
            return loginLogs.size();
        }
    }

    public void getLoginLogs(List<LoginLog> dataList) throws QueueIsEmptyException, InterruptedException {
        synchronized (loginLogs) {
            if (loginLogs.isEmpty()) {
                loginLogStatus = true;
                try {
                    loginLogs.wait(5000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw e;
                }
                if (!loginLogs.isEmpty()) {
                    loginLogStatus = false;
                    fillLoginLogs(dataList);
                    return;
                }
                throw new QueueIsEmptyException();
            } else {
                fillLoginLogs(dataList);
            }
        }
    }

    private void fillLoginLogs(List<LoginLog> dataList) {
        if (loginLogs.size() > 99) {
            int c = 0;
            while (!loginLogs.isEmpty()) {
                dataList.add(loginLogs.remove());
                c++;
                if (c > 99) {
                    break;
                }
            }
        } else {
            dataList.addAll(loginLogs);
            loginLogs.clear();
        }
    }

    public void addReceiveLog(ReceiveLog receiveLog) {
        synchronized (receiveLogs) {
            receiveLogs.add(receiveLog);
            if (receiveLogStatus) {
                receiveLogStatus = false;
                receiveLogs.notifyAll();
            }
        }
    }

    public int getReceiveLogSize() {
        synchronized (receiveLogs) {
            return receiveLogs.size();
        }
    }

    public void getReceiveLogs(List<ReceiveLog> dataList) throws QueueIsEmptyException, InterruptedException {
        synchronized (receiveLogs) {
            if (receiveLogs.isEmpty()) {
                receiveLogStatus = true;
                try {
                    receiveLogs.wait(5000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw e;
                }
                if (!receiveLogs.isEmpty()) {
                    receiveLogStatus = false;
                    fillReceiveLogs(dataList);
                    return;
                }
                throw new QueueIsEmptyException();
            } else {
                fillReceiveLogs(dataList);
            }
        }
    }

    private void fillReceiveLogs(List<ReceiveLog> dataList) {
        if (receiveLogs.size() > 99) {
            int c = 0;
            while (!receiveLogs.isEmpty()) {
                dataList.add(receiveLogs.remove());
                c++;
                if (c > 99) {
                    break;
                }
            }
        } else {
            dataList.addAll(receiveLogs);
            receiveLogs.clear();
        }
    }

    public void addSendLog(SendLog sendLog) {
        synchronized (sendLogs) {
            sendLogs.add(sendLog);
            if (sendLogStatus) {
                sendLogStatus = false;
                sendLogs.notifyAll();
            }
        }
    }

    public int getSendLogSize() {
        synchronized (sendLogs) {
            return sendLogs.size();
        }
    }

    public void getSendLogs(List<SendLog> dataList) throws QueueIsEmptyException, InterruptedException {
        synchronized (sendLogs) {
            if (sendLogs.isEmpty()) {
                sendLogStatus = true;
                try {
                    sendLogs.wait(5000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw e;
                }
                if (!sendLogs.isEmpty()) {
                    sendLogStatus = false;
                    fillSendLogs(dataList);
                    return;
                }
                throw new QueueIsEmptyException();
            } else {
                fillSendLogs(dataList);
            }
        }
    }

    private void fillSendLogs(List<SendLog> dataList) {
        if (sendLogs.size() > 99) {
            int c = 0;
            while (!sendLogs.isEmpty()) {
                dataList.add(sendLogs.remove());
                c++;
                if (c > 99) {
                    break;
                }
            }
        } else {
            dataList.addAll(sendLogs);
            sendLogs.clear();
        }
    }

    public void startup() {
        DataLogService dataLogService = SpringContextHolder.getBean(DataLogService.class);
        LoginLogService loginLogService = SpringContextHolder.getBean(LoginLogService.class);
        OperatorLogService operatorLogService = SpringContextHolder.getBean(OperatorLogService.class);
        ReceiveLogService receiveLogService = SpringContextHolder.getBean(ReceiveLogService.class);
        SendLogService sendLogService = SpringContextHolder.getBean(SendLogService.class);

        int c = 1;
        for (int i = 0; i < c; i++) {
            ProcessDataLogThread processDataLogThread = new ProcessDataLogThread(i + 1, dataLogService);
            processDataLogThread.start();
            processDataLogThreadList.add(processDataLogThread);

            ProcessLoginLogThread processLoginLogThread = new ProcessLoginLogThread(i + 1, loginLogService);
            processLoginLogThread.start();
            processLoginLogThreadList.add(processLoginLogThread);

            ProcessOperatorLogThread processOperatorLogThread = new ProcessOperatorLogThread(i + 1, operatorLogService);
            processOperatorLogThread.start();
            processOperatorLogThreadList.add(processOperatorLogThread);

            ProcessReceiveLogThread processReceiveLogThread = new ProcessReceiveLogThread(i + 1, receiveLogService);
            processReceiveLogThread.start();
            processReceiveLogThreadList.add(processReceiveLogThread);

            ProcessSendLogThread processSendLogThread = new ProcessSendLogThread(i + 1, sendLogService);
            processSendLogThread.start();
            processSendLogThreadList.add(processSendLogThread);
        }
    }

    public void shutdown() {
        for (ProcessDataLogThread processDataLogThread : processDataLogThreadList) {
            processDataLogThread.doDone();
        }
        for (ProcessLoginLogThread processLoginLogThread : processLoginLogThreadList) {
            processLoginLogThread.doDone();
        }
        for (ProcessOperatorLogThread processOperatorLogThread : processOperatorLogThreadList) {
            processOperatorLogThread.doDone();
        }
        for (ProcessReceiveLogThread processReceiveLogThread : processReceiveLogThreadList) {
            processReceiveLogThread.doDone();
        }
        for (ProcessSendLogThread processSendLogThread : processSendLogThreadList) {
            processSendLogThread.doDone();
        }
        notifySte();
    }

    public void notifySte() {
        synchronized (dataLogs) {
            dataLogs.notifyAll();
        }
        synchronized (loginLogs) {
            loginLogs.notifyAll();
        }
        synchronized (operatorLogs) {
            operatorLogs.notifyAll();
        }
        synchronized (receiveLogs) {
            receiveLogs.notifyAll();
        }
        synchronized (sendLogs) {
            sendLogs.notifyAll();
        }
    }
}
